package main

import (
	"bufio"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"syscall"
	"time"
)

// 配置
const (
	versionURL = "https://example.com/path/to/version" // 远程版本号文件的URL
	baseURL    = "https://example.com/path/to/files/"  // 更新文件的基础URL
	currentVersion = "1.0.0"                           // 当前版本
)

// 获取远程版本号文件内容
func getRemoteVersionFile() (string, error) {
	resp, err := http.Get(versionURL)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	// 读取远程版本号文件内容
	versionData, err := io.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}
	return string(versionData), nil
}

// 根据操作系统和架构获取匹配的文件名
func getTargetFilename() string {
	arch := runtime.GOARCH
	os := runtime.GOOS

	switch os {
	case "linux":
		switch arch {
		case "arm64":
			return "datax_Linux_arm64.tar.gz"
		case "arm":
			return "datax_Linux_armv7.tar.gz" // 假设为ARMv7
		case "amd64":
			return "datax_Linux_x86_64.tar.gz"
		}
	case "windows":
		if arch == "amd64" {
			return "datax_Windows_x86_64.zip"
		}
	}

	return ""
}

// 解析远程版本号文件，获取对应文件的SHA256校验值
func parseVersionFile(versionData, targetFile string) (string, error) {
	scanner := bufio.NewScanner(strings.NewReader(versionData))
	for scanner.Scan() {
		line := scanner.Text()
		parts := strings.Fields(line)
		if len(parts) != 2 {
			continue
		}
		if parts[1] == targetFile {
			return parts[0], nil
		}
	}
	return "", fmt.Errorf("未找到匹配的文件: %s", targetFile)
}

// 计算文件的SHA256哈希值
func calculateSHA256(filePath string) (string, error) {
	file, err := os.Open(filePath)
	if err != nil {
		return "", err
	}
	defer file.Close()

	hash := sha256.New()
	if _, err := io.Copy(hash, file); err != nil {
		return "", err
	}

	return hex.EncodeToString(hash.Sum(nil)), nil
}

// 下载更新文件
func downloadUpdate(url, dest string) error {
	resp, err := http.Get(url)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	// 创建目标文件
	out, err := os.Create(dest)
	if err != nil {
		return err
	}
	defer out.Close()

	// 将响应的内容写入目标文件
	_, err = io.Copy(out, resp.Body)
	return err
}

// 重启程序
func restartProgram(newBinaryPath string) error {
	// 获取当前执行文件的路径
	executable, err := os.Executable()
	if err != nil {
		return err
	}

	// 替换当前程序为新的程序
	err = os.Rename(newBinaryPath, executable)
	if err != nil {
		return err
	}

	// 重启程序
	return syscall.Exec(executable, os.Args, os.Environ())
}

func main() {
	log.Println("检查更新中...")

	// 获取远程版本号文件内容
	versionData, err := getRemoteVersionFile()
	if err != nil {
		log.Fatalf("获取远程版本失败: %v", err)
	}

	// 获取与当前系统架构匹配的文件名
	targetFile := getTargetFilename()
	if targetFile == "" {
		log.Fatalln("无法确定要下载的文件。")
	}

	// 解析远程版本文件以获取对应文件的SHA256哈希值
	expectedHash, err := parseVersionFile(versionData, targetFile)
	if err != nil {
		log.Fatalf("解析远程版本文件失败: %v", err)
	}

	// 临时文件存储路径
	tempFile := filepath.Join(os.TempDir(), targetFile)

	// 下载更新文件
	updateURL := baseURL + targetFile
	err = downloadUpdate(updateURL, tempFile)
	if err != nil {
		log.Fatalf("下载更新失败: %v", err)
	}

	log.Println("更新下载完成，正在校验文件...")

	// 计算下载文件的SHA256哈希值
	fileHash, err := calculateSHA256(tempFile)
	if err != nil {
		log.Fatalf("计算文件哈希失败: %v", err)
	}

	// 检查文件的哈希值是否匹配
	if fileHash != expectedHash {
		log.Fatalf("文件校验失败，预期哈希: %s，实际哈希: %s", expectedHash, fileHash)
	}

	log.Println("文件校验通过，正在应用更新...")

	// 重新启动程序
	err = restartProgram(tempFile)
	if err != nil {
		log.Fatalf("应用更新失败: %v", err)
	}

	log.Println("更新应用成功，程序重新启动。")

	// 模拟程序的正常运行
	for {
		log.Println("程序运行中...")
		time.Sleep(10 * time.Second)
	}
}
